package org.apache.rocketmq.remoting.jinggo.lg.ch08;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;

/**
 * @version 1.0.0
 * @Author wangyj
 * @Description Netty 长度域解码器 LengthFieldBasedFrameDecoder
 * @Date 2021/1/18
 */
public class EchoServer3 {

    // 长度字段的偏移量，也就是存放长度数据的起始位置
    private final int lengthFieldOffset = 0;
    // 长度字段所占用的字节数
    private final int lengthFieldLength = 0;

    /*
     * 消息长度的修正值
     *
     * 在很多较为复杂一些的协议设计中，长度域不仅仅包含消息的长度，而且包含其他的数据，如版本号、数据类型、数据状态等，那么这时候我们需要使用 lengthAdjustment 进行修正
     *
     * lengthAdjustment = 包体的长度值 - 长度域的值
     *
     */
    private final int lengthAdjustment = 0;
    // 解码后需要跳过的初始字节数，也就是消息内容字段的起始位置
    private final int initialBytesToStrip=0;
    // 长度字段结束的偏移量，lengthFieldEndOffset = lengthFieldOffset + lengthFieldLength
    private final int lengthFieldEndOffset=0;



    public void startEchoServer(int port) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        /**
         * 特殊分隔符解码器 DelimiterBasedFrameDecoder
         *
         * 使用特殊分隔符解码器 DelimiterBasedFrameDecoder 之前我们需要了解以下几个属性的作用。
         *
         *     delimiters
         *
         * delimiters 指定特殊分隔符，通过写入 ByteBuf 作为参数传入。delimiters 的类型是 ByteBuf 数组，所以我们可以同时指定多个分隔符，但是最终会选择长度最短的分隔符进行消息拆分。
         */
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) {
                            ByteBuf delimiter = Unpooled.copiedBuffer("&".getBytes());
                            ch.pipeline().addLast(new DelimiterBasedFrameDecoder(10, true, true, delimiter));
                            ch.pipeline().addLast(new EchoServerHandler());
                        }
                    });
            ChannelFuture f = b.bind(port).sync();
            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        new EchoServer3().startEchoServer(8088);
    }
}
